package com.sharding.test.util;

import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

import java.lang.reflect.*;

public class ReflectionUtils {

    private final static Log logger = LogFactory.getLog(ReflectionUtils.class);


    /**
     * 直接设置对象属性值，无视private/protected修饰符，不经过setter函数
     *
     * @param object
     * @param fieldName
     */
    public static void setFieldValue(final Object object, final String fieldName, final Object value) {
        Field field = getDeclaredField(object, fieldName);

        if (field == null)
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");

        makeAccessible(field);

        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
        }
    }

    /**
     * 直接读取对象属性值，无视private/protected修饰符，不经过getter函数
     *
     * @param object
     * @param fieldName
     * @return
     */
    public static Object getFieldValue(final Object object, final String fieldName) {
        Field field = getDeclaredField(object, fieldName);

        if (field == null)
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");

        makeAccessible(field);

        Object result = null;
        try {
            result = field.get(object);
        } catch (IllegalAccessException e) {
        }

        return result;
    }

    /**
     * 通过反射，获得Class定义中声明的父类的泛型参数的类型
     *
     * @param clazz
     * @param index
     * @return
     */
    public static Class getSuperClassGenericType(final Class clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superClass not ParameterizedType");
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index > params.length || index < 0) {
            logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
            return Object.class;
        }

        if (!(params[index] instanceof Class)) {
            logger.warn(clazz.getSimpleName() + " not set actual class on superClass generic parameter");
            return Object.class;
        }

        return (Class) params[index];
    }


    /**
     * 循环向上转型，获取对象的DeclaredField
     *
     * @param object
     * @param fieldName
     * @return
     */
    protected static Field getDeclaredField(final Object object, final String fieldName) {
        for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
            }
        }
        return null;
    }

    /**
     * 循环向上转型，获取对象的DeclaredMethod
     *
     * @param object
     * @param methodName
     * @param parameterType
     * @return
     */
    protected static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterType) {
        for (Class<?> superClass = object.getClass(); superClass != null; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredMethod(methodName, parameterType);
            } catch (NoSuchMethodException e) {
            }
        }
        return null;
    }

    protected static void makeAccessible(final Field field) {
        if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
            field.setAccessible(true);
        }
    }




}
